package com.xteam.xnetworkdisk.sys.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;


import com.xteam.xnetworkdisk.common.CurrentUser;
import com.xteam.xnetworkdisk.constant.Constant;
import com.xteam.xnetworkdisk.constant.FIleTypeConstant;
import com.xteam.xnetworkdisk.dto.FilePageByTypeDTO;
import com.xteam.xnetworkdisk.dto.FilePageDTO;
import com.xteam.xnetworkdisk.dto.FileRenameDTO;
import com.xteam.xnetworkdisk.utils.*;

import com.xteam.xnetworkdisk.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.xteam.xnetworkdisk.sys.entity.FileEntity;
import com.xteam.xnetworkdisk.sys.service.FileService;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;


/**
 * 文件控制器类
 * 处理文件相关的请求
 *
 * 作者：xiaozhiyong
 * 邮箱：xiaozhiyong03@gmail.com
 * 日期：2024-08-04 15:56:30
 */
@Slf4j
@RestController
@RequestMapping("sys/file")
@RequiredArgsConstructor
public class FileController {
    @Autowired
    private FileService fileService;

//    @Resource
//    private MinioUtilsNew minioUtils;

//    @Autowired
//    private AmqpTemplate rabbitTemplate;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 获取文件和目录列表（分页）
     *
     * @param filePageDTO 请求参数
     * @return 文件分页信息
     */
    @PostMapping("/listPage")
    public R list(@RequestBody FilePageDTO filePageDTO){
        R result = fileService.filePageQuery(filePageDTO);
        return result;
    }

    /**
     * 根据类别从查询文件
     * @param filePageByTypeDTO
     * @return
     */
    @PostMapping("/listPageByType")
    public R listPageByType(@RequestBody FilePageByTypeDTO filePageByTypeDTO, HttpSession session){
        Integer userid = (Integer) session.getAttribute("userid");
//        Integer userid = 1785409564;
        R result = fileService.listPageByType(filePageByTypeDTO,userid);
        return result;
    }


    /**
     * 根据类别从查询文件
     * @return
     */
    @GetMapping("/getRecycleBin")
    public R getRecycleBin(HttpSession session){
        Integer userid = (Integer) session.getAttribute("userid");
//        Integer userid = 1785409564;
        R result = fileService.getRecycleBin(userid);
        return result;
    }


    /**
     * 发送邮件
     * @param sendFileByEmailVO
     * @return
     */
    @PostMapping("/sendFileByEmail")
    public R sendFileByEmail(@RequestBody SendFileByEmailVO sendFileByEmailVO){
        R result = fileService.sendFileByEmail(sendFileByEmailVO);
        return result;
    }


    /**
     * 获取文件信息
     *
     * @param fId 文件ID
     * @return 文件信息
     */
    @GetMapping("/info/{fId}")
    public R info(@PathVariable("fId") Integer fId){
        FileEntity file = fileService.getById(fId);
//        Integer userid = 1785409564;
        Integer userid =  CurrentUser.getCurrentUserId();
        if(!file.getUserId().equals(userid)){
            return R.error(Constant.USER_NOT_AUTHENTICATED);
        }
        return R.ok().put("file", file);
    }

    @GetMapping("/view/{fileId}")
    public void fileView(@PathVariable Integer fileId, HttpServletResponse response){
        fileService.fileView(fileId,response);
    }

    /**
     * 分片上传
     * @param chunkFile
     * @param md5
     * @param folderId
     * @param chunkIndex
     * @param chunks
     * @param fileName
     * @param fileSize
     * @return
     */
    @PostMapping("/uploadChunk")
    public R uploadChunk(@RequestParam("chunkFile") MultipartFile chunkFile,@RequestParam("md5") String md5,
                         @RequestParam("folderId") Integer folderId, @RequestParam("chunkIndex") Integer chunkIndex,
                         @RequestParam("chunks") Integer chunks, @RequestParam("fileName") String fileName,
                         @RequestParam("fileSize") Long fileSize,HttpSession session){
        System.out.println("接收到分片");
        System.out.println("md5:"+ md5);
        System.out.println("index"+ chunkIndex);
        System.out.println("chunks"+ chunks);
        Integer userid = (Integer) session.getAttribute("userid");

        R result = fileService.uploadChunk(chunkFile,md5,folderId,chunkIndex,chunks,fileName,fileSize, userid);

        return result;
    }

    /**
     * 新建目录
     * @param createFolderVO
     * @return
     */
    @PostMapping("/createFolder")
    public R createFolder(@RequestBody CreateFolderVO createFolderVO,HttpSession session) {
        Integer userid = (Integer) session.getAttribute("userid");
//        Integer userid = 1785409564;
        R result = fileService.createFolder(createFolderVO,userid);
        return result;
    }

    /**
     * 判断是否可以进行视频的预览
     * @param md5
     * @return
     */
    @GetMapping("/judgePreview")
    public R judgePreview(@RequestParam("md5") String md5) {
        R result = fileService.judgePreview(md5);
        return result;
    }


    /**
     * 重命名文件
     *
     * @param fileRenameDTO 文件信息
     *
     * @return 重命名结果
     */
    @PostMapping("/rename")
    public R renameFile(@RequestBody FileRenameDTO fileRenameDTO) {
        fileService.rename(fileRenameDTO);
        return R.ok("重命名成功");
    }



    /**
     * 提供文件id和目标目录移动文件
     * @param moveFileVO
     * @return
     */
    @PostMapping("/move")
    public R moveFile(@RequestBody MoveFileVO moveFileVO) {
        R result = fileService.moveFile(moveFileVO);
        return result;
    }

    /**
     * 获取目录
     * @param fileId
     * @param session
     * @return
     */
    @GetMapping("/getDir")
    public R getDir(@RequestParam Integer fileId,HttpSession session) {
        Integer userid = (Integer) session.getAttribute("userid");
//        Integer userid = 1;
        R result = fileService.getDir(fileId,userid);
        return result;
    }

    /**
     * 创建下载链接
     *
     * @param fileId 文件ID
     * @return 下载链接
     */
    @GetMapping("/createDownloadLink")
    public R createDownloadLink(@RequestParam String fileId) {
        R result = fileService.createDownloadLink(fileId);
        // 这里实现创建下载链接的逻辑
        return result;
    }

    /**
     * 尝试删除文件
     *
     * @param fileIds 文件ID
     * @return 删除结果
     */
    @PostMapping("/deleteTry")
    public R deleteFileTry(@RequestBody List<Integer> fileIds) {
        R result = fileService.deleteFileTry(fileIds);
        return result;
    }

    /**
     * 真正删除文件
     *
     * @param fileIds 文件ID
     * @return 删除结果
     */
    @PostMapping("/delete")
    public R deleteFile(@RequestBody List<Integer> fileIds) {
        R result = fileService.deleteFile(fileIds);
        return result;
    }


    /**
     * 根据文件类型获取分类
     * @return
     */
    @GetMapping("/getFileType")
    public R getFileType() {
        Map<String, Integer> fileTypes = new HashMap<>();
        fileTypes.put("image", FIleTypeConstant.IMAGE);
        fileTypes.put("video", FIleTypeConstant.VIDEO);
        fileTypes.put("all", FIleTypeConstant.ALL);
        fileTypes.put("audio",FIleTypeConstant.AUDIO);
        fileTypes.put("document",FIleTypeConstant.DOCUMENT);
        fileTypes.put("other", FIleTypeConstant.OTHER);
        return R.ok().put("fileTypes",fileTypes);
    }


    /**
     * 恢复文件
     * @param fileIds
     * @return
     */
    @PostMapping("/recover")
    public R recover(@RequestBody List<Integer> fileIds) {
        R result = fileService.recover(fileIds);
        // 这里实现文件分片上传的逻辑
        return result;
    }


    /**
     * 秒传
     * @param instantUploadVO
     * @return
     */
    @PostMapping("/instantUpload")
    public R instantUpload(@RequestBody InstantUploadVO instantUploadVO) {
        R result = fileService.instantUpload(instantUploadVO);
        return result;
    }

    /**
     * 判断文件状态
     * @param md5Value
     * @return
     */
    @GetMapping("/determineUploadStrategy")
    public R determineUploadStrategy(@RequestParam("md5") String md5Value) {
        R result = fileService.determineUploadStrategy(md5Value);
        return result;
    }

    /**
     * 取消文件上传
     * @param canselUploadVO
     * @return
     */
    @PostMapping("/canselUpload")
    public R canselUpload(@RequestBody CanselUploadVO canselUploadVO) {
        R result = fileService.canselUpload(canselUploadVO);
        return result;
    }


/**
 * 处理并发的文件分片上传
 */

    /**
     * 并发文件上传/线程池
     * @param chunkFile
     * @param md5
     * @param folderId
     * @param chunkIndex
     * @param chunks
     * @param fileName
     * @param fileSize
     * @return
     */
    @PostMapping("/uploadChunkThreads")
    public R concurrentUploadChunk(@RequestParam("chunkFile") MultipartFile chunkFile,@RequestParam("md5") String md5,
                         @RequestParam("folderId") Integer folderId, @RequestParam("chunkIndex") Integer chunkIndex,
                         @RequestParam("chunks") Integer chunks, @RequestParam("fileName") String fileName,
                         @RequestParam("fileSize") Long fileSize,HttpSession session){
        Integer userid = (Integer) session.getAttribute("userid");
//        通过线程池进行调用
        ExecutorService executorService = ThreadPoolManager.getExecutorService();
        // 提交任务，并将 Future 对象存储在 Map 中
        Future<?> future = executorService.submit(() -> {
            fileService.uploadChunk(chunkFile, md5, folderId, chunkIndex, chunks, fileName, fileSize,userid);
        });
        uploadTasks.put(md5 + chunkIndex, future);

        return R.ok();
    }

    /**
     * 取消未开始的分片上传任务
     * @param md5
     * @return
     */
    @GetMapping("/cancelChunckUploads")
    public R cancelPendingUploads(@RequestParam("md5") String md5) {
        uploadTasks.forEach((taskKey, future) -> {
            // 检查任务键的前32个字符是否匹配指定的 MD5 值，并且任务尚未完成或取消
            if (taskKey.startsWith(md5) && taskKey.length() >= 32 && !future.isDone() && !future.isCancelled()) {
                // 取消未开始的任务
                future.cancel(false); // 使用 false 参数，这样不会中断已经开始的任务
                uploadTasks.remove(taskKey); // 从任务列表中移除
            }
        });
        return R.ok();
    }





    // 用于存储每个上传任务的 Future 对象
    private ConcurrentHashMap<String, Future<?>> uploadTasks = new ConcurrentHashMap<>();

    public R concurrentUploadChunkMQ(@RequestParam("chunkFile") MultipartFile chunkFile,@RequestParam("md5") String md5,
                                   @RequestParam("folderId") Integer folderId, @RequestParam("chunkIndex") Integer chunkIndex,
                                   @RequestParam("chunks") Integer chunks, @RequestParam("fileName") String fileName,
                                   @RequestParam("fileSize") Long fileSize){

        //使用RabbitMQ缓解高并发

        // 将分片信息封装为消息并发送到RabbitMQ
        UploadChunkMessageVO message = null;
        try {
            message = new UploadChunkMessageVO(chunkFile.getBytes(), md5, folderId, chunkIndex, chunks, fileName, fileSize);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        rabbitTemplate.convertAndSend("upload.exchange", "upload.routing.key", message);

        return R.ok("分片上传任务已提交");

    }



}
